package com.zwl.SpringBootAndroid.server;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import com.zwl.SpringBootAndroid.message.BaseMessage;
import com.zwl.SpringBootAndroid.message.BindMessage;
import com.zwl.SpringBootAndroid.message.ChatMessageType;
import com.zwl.SpringBootAndroid.util.LogUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;

import java.util.*;

/**
 * socket数据处理
 *
 * @author 万祥新
 *
 */
public class SocketChannelHandler extends SimpleChannelInboundHandler<String> {
    private static HashMap<String, Channel> channelMap = new LinkedHashMap<>();
    private static final String CLIENT_ID = "client_id";
    private static Gson gson = new Gson();
    private static String missage="";
    @Override
    protected void channelRead0(ChannelHandlerContext arg0, String arg1) {

        String chatType = new JsonParser().parse(arg1).getAsJsonObject().get("chatType").getAsString();
        if (ChatMessageType.MSG_TYPE_BIND.name().equals(chatType)) {
            BindMessage message = gson.fromJson(arg1, BindMessage.class);
            LogUtil.log("绑定设备>>>" + message.clientId);
            channelMap.put(message.clientId, arg0.channel());
            arg0.channel().attr(AttributeKey.valueOf(CLIENT_ID)).set(message.clientId);
        } else if (ChatMessageType.MSG_TYPE_PING.name().equals(chatType)) {
            LogUtil.log("收到客户端发送过来的心跳>>>" + getClientId(arg0));
        } else if (ChatMessageType.MSG_TYPE_NORMAL.name().equals(chatType)) {
            LogUtil.log("接收到了客户端" + getClientId(arg0) + "的真实数据>>>" + arg1);
            parseMessage(gson.fromJson(arg1, BaseMessage.class));
        } else {
            LogUtil.log("接收到了设备" + getClientId(arg0) + "数据>>>" + arg1);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx){
        String clientId = getClientId(ctx);
        LogUtil.log("设备" + clientId + "退出了>>>" + clientId);
        channelMap.remove(clientId);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        super.exceptionCaught(ctx, cause);
        LogUtil.log("设备 " + getClientId(ctx) + " 异常>>>" + cause.getMessage());
        ctx.channel().close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        if (evt instanceof IdleStateEvent) {
            LogUtil.log("设备 " + getClientId(ctx) + " 没发心跳，要被关闭了");
            ctx.channel().close();
        }
    }

    private void parseMessage(BaseMessage messages) {
        // 正常消息，自己处理
        missage=messages.content;
    }

    public static int closeAll() {
        int size = channelMap.size();
        for (Channel channel: channelMap.values()) {
            channel.close();
        }
        return size;
    }

    public static int broadcastToAll(String content) {
        if (content == null || content.isEmpty()) return 0;
        int size = channelMap.size();
        for (Channel channel: channelMap.values()) {
            BaseMessage message = new BaseMessage();
            message.content = content;
            channel.writeAndFlush(gson.toJson(message));
        }
        return size;
    }

    public static boolean broadcastToClientId(String clientId, String content) {
        if (clientId == null || content == null) return false;
        Channel channel = channelMap.get(clientId);
        if (channel != null) {
            BaseMessage message = new BaseMessage();
            message.content = content;
            channel.writeAndFlush(gson.toJson(message));
            return true;
        }
        return false;
    }

    public static Object getConnectInfo() {
        List<Object> out = new ArrayList<>();
        for (Map.Entry<String, Channel> entry: channelMap.entrySet()){
            JsonObject obj = new JsonObject();
            obj.addProperty("clientId", entry.getKey());
            obj.addProperty("channel", entry.getValue().toString());
            obj.addProperty("content", missage);
            out.add(obj);
        }
        return out;
    }

    public static String getClientId(Channel channel) {
        return (String) channel.attr(AttributeKey.valueOf(CLIENT_ID)).get();
    }

    public static String getClientId(ChannelHandlerContext ctx) {
        return (String) ctx.channel().attr(AttributeKey.valueOf(CLIENT_ID)).get();
    }
}
